package com.bumptech.glide.load.model;

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.text.TextUtils;

import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.load.data.mediastore.MediaStoreUtil;
import com.bumptech.glide.signature.ObjectKey;

import java.io.File;
import java.io.FileNotFoundException;

/**
 * Loads the file path for {@link MediaStore} owned {@link Uri uris}.
 * <p>
 * 通过{@link MediaStore}的{@link Uri}来加载文件路径
 */
public final class MediaStoreFileLoader implements ModelLoader<Uri, File> {

    private final Context context;

    // Public API.
    @SuppressWarnings("WeakerAccess")
    public MediaStoreFileLoader(Context context) {
        this.context = context;
    }

    @Override
    public LoadData<File> buildLoadData(@NonNull Uri uri, int width, int height,
                                        @NonNull Options options) {
        return new LoadData<>(new ObjectKey(uri), new FilePathFetcher(context, uri));
    }

    @Override
    public boolean handles(@NonNull Uri uri) {
        return MediaStoreUtil.isMediaStoreUri(uri);
    }

    private static class FilePathFetcher implements DataFetcher<File> {
        private static final String[] PROJECTION = new String[]{
                MediaStore.MediaColumns.DATA,
        };

        private final Context context;
        private final Uri uri;

        FilePathFetcher(Context context, Uri uri) {
            this.context = context;
            this.uri = uri;
        }

        @Override
        public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super File> callback) {
            Cursor cursor = context.getContentResolver().query(uri, PROJECTION, null /*selection*/,
                    null /*selectionArgs*/, null /*sortOrder*/);

            String filePath = null;
            if (cursor != null) {
                try {
                    if (cursor.moveToFirst()) {
                        filePath = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA));
                    }
                } finally {
                    cursor.close();
                }
            }

            if (TextUtils.isEmpty(filePath)) {
                callback.onLoadFailed(new FileNotFoundException("Failed to find file path for: " + uri));
            } else {
                callback.onDataReady(new File(filePath));
            }
        }

        @Override
        public void cleanup() {
            // Do nothing.
        }

        @Override
        public void cancel() {
            // Do nothing.
        }

        @NonNull
        @Override
        public Class<File> getDataClass() {
            return File.class;
        }

        @NonNull
        @Override
        public DataSource getDataSource() {
            return DataSource.LOCAL;
        }
    }

    /**
     * {@link ModelLoaderFactory} for {@link MediaStoreFileLoader}s.
     */
    public static final class Factory implements ModelLoaderFactory<Uri, File> {

        private final Context context;

        public Factory(Context context) {
            this.context = context;
        }

        @NonNull
        @Override
        public ModelLoader<Uri, File> build(MultiModelLoaderFactory multiFactory) {
            return new MediaStoreFileLoader(context);
        }

        @Override
        public void teardown() {
            // Do nothing.
        }
    }
}
